/*
 * Copyright (C) 2007-2008  Hylke van der Schaaf
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, in version 3 of the License.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package hextd.core;

import com.twolattes.json.Entity;
import com.twolattes.json.Json;
import com.twolattes.json.Marshaller;
import com.twolattes.json.TwoLattes;
import com.twolattes.json.Value;
import hextd.server.PlayerInfo;
import hextd.tower.JsonTower;
import hextd.tower.TowerFactory;
import hextd.util.MapIO;
import java.io.BufferedReader;
import java.io.StringReader;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;

@Entity
public class MapInfo {

	static private Marshaller<GameMap> marshaller;
	@Value
	public int mapId;
	@Value
	public String title;
	@Value
	public int lastChange;
	@Value
	public int players;
	@Value(optional = true)
	public int category = 0;
	@Value(optional = true)
	public List<Integer> preReq = new ArrayList<Integer>();
	@Value(optional = true, name = "nm")
	public int nextMap = 0;
	//
	public int waves;
	public String fileName;
	public String expectedMD5;
	private String content;
	private WeakReference<GameMap> mapDataCache;

	@Override
	public String toString() {
		return title;
	}

	public GameMap getMapData() {
		if (content != null) {
			GameMap mapData = null;
			if (mapDataCache != null) {
				mapData = mapDataCache.get();
			}
			if (mapData == null) {
				if (marshaller == null) {
					marshaller = TwoLattes.createMarshaller(GameMap.class);
				}
				try {
					Json.Value fromString = Json.fromString(content);
					mapData = marshaller.unmarshall((Json.Object) fromString);
				} catch (ClassCastException e) {
					System.out.println("MapInfo::getMapData: Not a valid JSon map!");
				} catch (IllegalArgumentException e) {
					System.out.println("MapInfo::getMapData: Not a valid JSon map!");
				}
				if (mapData == null) {
					mapData = MapIO.readLevel(new BufferedReader(new StringReader(content)));
				}
				mapDataCache = new WeakReference<GameMap>(mapData);
				players = 0;
				for (JsonTower t : mapData.getTowers()) {
					if (t.type == TowerFactory.type.homeBase) {
						players++;
					}
				}
				players = Math.max(players, 1);
				waves = mapData.waves.size();
				title = mapData.getTitle();
			}
			return mapData;
		} else {
			return null;
		}

	}

	public void setContent(String newContent) {
		content = newContent;
		mapDataCache = null;
	}

	public String getContent() {
		if (content != null) {
			GameMap mapData = getMapData();
			if (marshaller == null) {
				marshaller = TwoLattes.createMarshaller(GameMap.class);
			}
			Json.Value marshall = marshaller.marshall(mapData);
			return marshall.toString();
		} else {
			return null;
		}
	}

	public String getMapMD5() {
		if (content != null) {
			GameMap mapData = getMapData();
			if (marshaller == null) {
				marshaller = TwoLattes.createMarshaller(GameMap.class);
			}
			Json.Value marshall = marshaller.marshall(mapData);
			return MapIO.generateMD5(marshall.toString());
		} else {
			return "unknown";
		}
	}

	public boolean havePreReq(PlayerInfo p) {
		for (Integer pqMapId : preReq) {
			if (!p.maps.contains(pqMapId)) {
				return false;
			}
		}
		return true;
	}
}
